#include "commandClient.h"
#include "public.h"
#define HASHARR 65

int mkdirClient(const int SockFd,char *protocol)
{
    INFO_LOG("执行mkdirClient\n");

    char res[100] = { 0 };

    int ret = send(SockFd,protocol,strlen(protocol),0);
    //  日志信息
    switch (ret)
    {
    case 0:
        printf("服务器断开连接\n");
        ERROR_LOG("对方断开连接\n");
        return -1;
    case -1:
        printf("发送错误：mkdirClient发送protocol失败\n");
        ERROR_LOG("发送错误：mkdirClient发送protocol失败\n");
        return -1;
    }

    ret = recv(SockFd,res,sizeof(res),0);
    //  日志信息
    switch (ret)
    {
    case 0:
        printf("服务器断开连接\n");
        ERROR_LOG("对方断开连接\n");
        return -1;
    case -1:
        printf("接收错误：mkdirClient接收res失败\n");
        ERROR_LOG("接收错误：mkdirClient接收res失败\n");
        return -1;
    }

    if(strcmp(res,"创建成功\n") == 0)
    {
        printf("创建成功！\n");
        DEBUG_LOG("mkdirClient创建成功\n");
        return 0;
    }
    printf("创建失败!\n");
    ERROR_LOG("mkdirClient执行失败\n");

    return -1;
}

int pwdClient(const struct login_status *Status)
{
    printf("当前路径是：%s\n",Status->path);
    INFO_LOG("执行pwdClient\n");
    return 0;
}

int cdClient(int SockFd,char *protocol,struct login_status *Status)
{
    INFO_LOG("执行cdClient\n");
    char *agv[3] = { 0 };
    char pro[100] = { 0 };
    strcpy(pro,protocol);

    DEBUG_LOG("cdClient->protocol拷贝pro:%s\n",pro);
    getToken(pro,agv);

    char *name = agv[0];
    char *path = agv[1];
    char *param = agv[2];

    DEBUG_LOG("cdClient->切割信息：name:%s,path:%s,param:%s\n",name,path,param);

    char temp[100] = { 0 };
    char res[10] = { 0 };

    int ret = send(SockFd,protocol,strlen(protocol),0);
    // 日志信息
    switch (ret)
    {
    case 0:
        printf("服务器断开连接\n");
        ERROR_LOG("对方断开连接\n");
        return -1;
    case -1:
        printf("发送错误：cdClient发送protocol失败\n");
        ERROR_LOG("发送错误：cdClient发送protocol失败\n");
        return -1;
    }
    if(strcmp(param,"..") == 0)
    {
        int len = strlen(path);
        for(int i = len;i >= 0;i--)
        {
            // 路径名前无"/"->+2,有杠->+3
            if(path[i] == '/')
            {   
                for(int j = i;j < len;j++)
                    path[j] = '\0';

                printf("%s >",path);
                fflush(stdout);
                strcpy(Status->path,path);

                DEBUG_LOG("cdClient执行成功\n");

                return 0;
            }
        }
    }
    else if(strcmp(param,"~") == 0)
    {

        printf("%s >",name);
        fflush(stdout);

        strcpy(Status->path,name);

        DEBUG_LOG("cdClient执行成功\n");

        return 0;
    }
    else
    {
        ret = recv(SockFd,res,sizeof(temp),0);
        // 日志信息
        switch (ret)
        {
        case 0:
            printf("服务器断开连接\n");
            ERROR_LOG("对方断开连接\n");
            return -1;
        case -1:
            printf("发送错误：cdClient接收res返回值失败\n");
            ERROR_LOG("发送错误：cdClient接收res返回值失败\n");
            return -1;
        }
        if(strcmp(res,"成功\n") == 0)
        {
            strcat(temp,path);
            strcat(temp,"/");
            strcat(temp,param);

            printf("%s >",temp);

            strcpy(Status->path,temp);

            fflush(stdout);
            DEBUG_LOG("cdClient执行成功\n");

            return 0;
        }
    }

    printf("cdClient执行失败\n");
    ERROR_LOG("cdClient执行失败\n");
    return -1;
}

int lsClient(const int SockFd,char *protocol)
{
    INFO_LOG("执行lsClient\n");
    char res[300] = { 0 };
    char *token;
    char s[] = "&";

    int ret = send(SockFd,protocol,strlen(protocol),0);
    // 日志信息
    switch (ret)
    {
    case 0:
        printf("服务器断开连接\n");
        ERROR_LOG("服务器断开连接\n");
        return -1;
    case -1:
        printf("发送错误：lsClient发送protocol失败\n");
        ERROR_LOG("发送错误：lsClient发送protocol失败\n");
        return -1;
    }

    ret = recv(SockFd,res,sizeof(res),0);
    // 日志信息
    switch (ret)
    {
    case 0:
        printf("服务器断开连接\n");
        ERROR_LOG("服务器断开连接\n");
        return -1;
    case -1:
        printf("接收错误：lsClient接收res返回值失败\n");
        ERROR_LOG("接收错误：lsClient接收res返回值失败\n");
        return -1;
    }

    token = strtok(res,s);

    while(token != NULL)
    {
        if(strcmp(token,".") != 0 && strcmp(token,"..") != 0)
            printf("%s\n",token);

        token = strtok(NULL,s);
    }

    INFO_LOG("执行lsClient成功\n");

    return 0;
}

//上传文件到服务器
int put_serverfile(int netfd, char* file_name, struct client_info* info){
    train_t train;

    bzero(&train, 0);
    //发送protocal
    train.len= sizeof(info->protocol);
    send(netfd, &train.len, sizeof(off_t), MSG_NOSIGNAL);
    memcpy(train.trainBuf, info->protocol, train.len);
    send(netfd, train.trainBuf, train.len, MSG_NOSIGNAL);
    char name[50]={0};
    sprintf(name,"../client/%s",file_name);
    INFO_LOG("%s\n",name);
    int file_fd = open(name, O_RDWR);
    if(file_fd == -1){
        printf("文件不存在，请检查输入后再试\n");
        send(netfd,&file_fd,sizeof(int),0);
        return 0;
    }
    char hash[HASHARR]={0};
    hash_file(file_fd,hash);
    //发送file_fd仅仅为判断是否打开文件，打开file_fd一定不为-1，无所谓多少
    send(netfd, &file_fd, sizeof(int), 0); 
    int num=strlen(hash);
    send(netfd,&num,sizeof(int),MSG_NOSIGNAL);
    send(netfd,hash,num,MSG_NOSIGNAL);
    int check_exit = -1;
    recv(netfd,&check_exit,sizeof(int),MSG_WAITALL);

    bzero(&train, 0);
    // 获得文件信息
    struct stat stat_file;
    fstat(file_fd, &stat_file);
    train.len = stat_file.st_size;
    switch(check_exit){
    case 1:
        printf("禁止创建同名文件！\n");
        break;
    case 2:

        int exist_size;
        recv(netfd, &exist_size, sizeof(int), 0);
        int odd_size = train.len - exist_size;
        send(netfd, &odd_size, sizeof(int), 0);
        lseek(file_fd, exist_size, SEEK_SET);
        if(odd_size > MMAPSIZE){
            void* addr = mmap(NULL, train.len, PROT_READ|PROT_WRITE, MAP_SHARED, file_fd, 0);
            if(addr == MAP_FAILED){
                error(1, errno, "mmap");
            }
            send(netfd, addr+exist_size, odd_size, 0);
            munmap(addr, train.len);
            INFO_LOG("断点续传成功\n");
        }else{
            //使用send发送文件
            while(1){
                //send(netfd, &train.buf, train.len, MSG_NOSIGNAL);
                ssize_t nbytes = read(file_fd, train.trainBuf, TRANINSIZE);
                if(nbytes == -1){
                    error(1, errno, "read");
                }
                if(nbytes < TRANINSIZE){
                    send(netfd, train.trainBuf,nbytes, 0);
                    printf("%s\n",train.trainBuf);
                    break;
                }
                send(netfd, &train.trainBuf, TRANINSIZE, MSG_NOSIGNAL);
            }
            printf("断点续传成功\n");
        }
        break;
    case 3:
        printf("极速秒传成功\n");
        break;
    case 4:
        // 发送文件大小
        send(netfd, &train.len, sizeof(off_t), MSG_NOSIGNAL);
        //lseek在hash 之后调整读取位置到开头
        lseek(file_fd,0,SEEK_SET);
        //mmap大文件传输
        if(train.len > MMAPSIZE){
            void* addr = mmap(NULL, train.len, PROT_READ|PROT_WRITE, MAP_SHARED, file_fd, 0);
            if(addr == MAP_FAILED){
                error(1, errno, "mmap");
            }
            send(netfd, addr, train.len, 0);
            munmap(addr, train.len);
        }else{
            //使用send发送文件
            while(1){
                //send(netfd, &train.buf, train.len, MSG_NOSIGNAL);
                ssize_t nbytes = read(file_fd, &train.trainBuf, TRANINSIZE);
                if(nbytes == -1){
                    error(1, errno, "read");
                }
                if(nbytes < TRANINSIZE){
                    send(netfd, &train.trainBuf, nbytes, MSG_NOSIGNAL);
                    break;
                }
                send(netfd, &train.trainBuf, TRANINSIZE, MSG_NOSIGNAL);
            }
        }
    printf("文件上传完成\n");
        break;
    default:
        printf("异常的文件传输状态码\n");
    }
    close(file_fd);
    return 0;
}

int get_serverfile(int netfd, char* file_name, struct client_info* info)
{
    train_t train;
    bzero(&train, 0);
    //发送protocal
    train.len= sizeof(info->protocol);
    send(netfd, &train.len, sizeof(off_t), MSG_NOSIGNAL);
    memcpy(train.trainBuf, info->protocol, train.len);
    send(netfd, train.trainBuf, train.len, MSG_NOSIGNAL);

    bzero(&train, 0);
    //接收文件是否存在的信息
    int file_status;
    recv(netfd,&file_status,sizeof(int),0);
    if(file_status == 0){
        printf("文件不存在，请检查输入后再试\n");
        return 0;
    }
    //接收文件大小
    recv(netfd, &train.len, sizeof(off_t),0);
    printf("filename_length=%d\n",train.len);
    //接收文件
    bzero(&train, 0);
    char file_path[HASHARR];
    sprintf(file_path,"../client/%s",file_name);
    int file_fd = open(file_path, O_CREAT|O_RDWR|O_TRUNC,0666);
    if(file_fd == -1){
        error(1, errno, "open");
    }
    if(train.len>MMAPSIZE)

    {
        INFO_LOG("使用mmap 进行文件传输\n");
        ftruncate(file_fd,train.len);
        char* addr = (char*)mmap(NULL,train.len,PROT_READ|PROT_WRITE,MAP_SHARED,file_fd,0);
        if(addr==NULL)
        {
            ERROR_LOG("文件映射失败\n");
        }
        size_t recvbytes=recv(netfd,addr,train.len,MSG_WAITALL);
        if(recvbytes==0)
        {
            ERROR_LOG("对方断开链接\n")
        }
        munmap(addr,train.len);
    }
    else
    {
        //收文件，文件大小为train.len
        while(1){
            ssize_t recvbytes = recv(netfd, train.trainBuf, TRANINSIZE,0);
            if(recvbytes == -1){
                perror("recv");
            }
            if(recvbytes < TRANINSIZE){
                ssize_t writebytes = write(file_fd,train.trainBuf,recvbytes);
                if(writebytes == -1){
                    perror("write");
                }
                break;
            }
            ssize_t writebytes = write(file_fd,train.trainBuf,recvbytes);
            if(writebytes == -1){
                perror("write");
            }
        }
    }
    close(file_fd);
    return 0;
}

int rmClient(const int SocketFd, const char* protocol, const char* token){

    int result = -1;
    int token_len = 0;

    token_len = strlen(token);


    send(SocketFd, &token_len, sizeof(int), MSG_NOSIGNAL);
    send(SocketFd, token, strlen(token), MSG_NOSIGNAL);

    send(SocketFd, protocol, strlen(protocol), MSG_NOSIGNAL);
    recv(SocketFd, &result, sizeof(int), 0);

    if(result == 1){
        printf("删除成功！\n");
    }

    if(result == 0){
        printf("删除失败！\n");
    }


    return 0;
}

int logoutClient(const int net_fd, struct login_status* stat){


    //printf("token: %s\n", stat->token);

    int token_len = strlen(stat->token);

    send(net_fd, &token_len, sizeof(int), MSG_NOSIGNAL);
    send(net_fd, stat->token, token_len, MSG_NOSIGNAL);

    int s = 0;
    recv(net_fd, &s, sizeof(int), 0);

    if(s == 1){
        stat->login = false;
        printf("注销成功\n");
        close(net_fd);
        return 0;
    }

    printf("注销失败\n");

    return 0;
}

